#include <type.h>
#include <string.h>
#include <assemble.h>
#include "process.h"


#define PORT_KB_DATA	0x60

#define KEY_ESC			0x01
#define KEY_BACKSPACE		'\b' //0x8
#define KEY_TAB			0x0F
#define KEY_ENTER		'\n' //0xA
#define KEY_CTRL_L		0x1D
#define KEY_SHIFT_L		0x2A
#define KEY_SHIFT_R		0x36
#define KEY_ALT_L		0x38
#define KEY_CAPS_LOCK		0x3A
#define KEY_F1			0x3B
#define KEY_F2			0x3C
#define KEY_F3			0x3D
#define KEY_F4			0x3E
#define KEY_F5			0x3F
#define KEY_F6			0x40
#define KEY_F7			0x41
#define KEY_F8			0x42
#define KEY_F9			0x43
#define KEY_F10			0x44
#define KEY_NUM_LOCK		0x45
#define KEY_SCROLL_LOCK		0x46
#define KEY_PAD_HOME		0x47
#define KEY_PAD_UP		0x48
#define KEY_PAD_PAGEUP		0x49
#define KEY_PAD_MINUS		0x4A
#define KEY_PAD_LEFT		0x4B
#define KEY_PAD_MID		0x4C
#define KEY_PAD_RIGHT		0x4D
#define KEY_PAD_PLUS		0x4E
#define KEY_PAD_END		0x4F
#define KEY_PAD_DOWN		0x50
#define KEY_PAD_PAGEDOWN	0x51
#define KEY_PAD_INS		0x52
#define KEY_PAD_DOT		0x53
#define KEY_F11			0x57
#define KEY_F12			0x58

#define KEY_PAD_ENTER		0xE1C
#define KEY_CTRL_R		0xE1D
#define KEY_PAD_SLASH		0xE35
#define KEY_ALT_R		0xE38
#define KEY_HOME		0xE47
#define KEY_UP			0xE48
#define KEY_PAGEUP		0xE49
#define KEY_LEFT		0xE4B
#define KEY_RIGHT		0xE4D
#define KEY_END			0xE4F
#define KEY_DOWN		0xE50
#define KEY_PAGEDOWN		0xE51
#define KEY_INSERT		0xE52
#define KEY_DELETE		0xE53
#define KEY_GUI_L		0xE5B
#define KEY_GUI_R		0xE5C
#define KEY_APPS		0xE5D


/* Keymap for US MF-2 keyboard. */
static u32_t keymap[][3] = {

/* scan-code			!Shift		Shift		E0 XX		*/
/* ==================================================================== */
/* 0x00 - none		*/	0,		0,		0,
/* 0x01 - ESC		*/	KEY_ESC,	KEY_ESC,	0,
/* 0x02 - '1'		*/	'1',		'!',		0,
/* 0x03 - '2'		*/	'2',		'@',		0,
/* 0x04 - '3'		*/	'3',		'#',		0,
/* 0x05 - '4'		*/	'4',		'$',		0,
/* 0x06 - '5'		*/	'5',		'%',		0,
/* 0x07 - '6'		*/	'6',		'^',		0,
/* 0x08 - '7'		*/	'7',		'&',		0,
/* 0x09 - '8'		*/	'8',		'*',		0,
/* 0x0A - '9'		*/	'9',		'(',		0,
/* 0x0B - '0'		*/	'0',		')',		0,
/* 0x0C - '-'		*/	'-',		'_',		0,
/* 0x0D - '='		*/	'=',		'+',		0,
/* 0x0E - BS		*/	KEY_BACKSPACE,	KEY_BACKSPACE,	0,
/* 0x0F - TAB		*/	KEY_TAB,	KEY_TAB,	0,
/* 0x10 - 'q'		*/	'q',		'Q',		0,
/* 0x11 - 'w'		*/	'w',		'W',		0,
/* 0x12 - 'e'		*/	'e',		'E',		0,
/* 0x13 - 'r'		*/	'r',		'R',		0,
/* 0x14 - 't'		*/	't',		'T',		0,
/* 0x15 - 'y'		*/	'y',		'Y',		0,
/* 0x16 - 'u'		*/	'u',		'U',		0,
/* 0x17 - 'i'		*/	'i',		'I',		0,
/* 0x18 - 'o'		*/	'o',		'O',		0,
/* 0x19 - 'p'		*/	'p',		'P',		0,
/* 0x1A - '['		*/	'[',		'{',		0,
/* 0x1B - ']'		*/	']',		'}',		0,
/* 0x1C - CR/LF		*/	KEY_ENTER,	KEY_ENTER,	KEY_PAD_ENTER,
/* 0x1D - l. Ctrl	*/	KEY_CTRL_L,	KEY_CTRL_L,	KEY_CTRL_R,
/* 0x1E - 'a'		*/	'a',		'A',		0,
/* 0x1F - 's'		*/	's',		'S',		0,
/* 0x20 - 'd'		*/	'd',		'D',		0,
/* 0x21 - 'f'		*/	'f',		'F',		0,
/* 0x22 - 'g'		*/	'g',		'G',		0,
/* 0x23 - 'h'		*/	'h',		'H',		0,
/* 0x24 - 'j'		*/	'j',		'J',		0,
/* 0x25 - 'k'		*/	'k',		'K',		0,
/* 0x26 - 'l'		*/	'l',		'L',		0,
/* 0x27 - ';'		*/	';',		':',		0,
/* 0x28 - '\''		*/	'\'',		'"',		0,
/* 0x29 - '`'		*/	'`',		'~',		0,
/* 0x2A - l. SHIFT	*/	KEY_SHIFT_L,	KEY_SHIFT_L,	0,
/* 0x2B - '\'		*/	'\\',		'|',		0,
/* 0x2C - 'z'		*/	'z',		'Z',		0,
/* 0x2D - 'x'		*/	'x',		'X',		0,
/* 0x2E - 'c'		*/	'c',		'C',		0,
/* 0x2F - 'v'		*/	'v',		'V',		0,
/* 0x30 - 'b'		*/	'b',		'B',		0,
/* 0x31 - 'n'		*/	'n',		'N',		0,
/* 0x32 - 'm'		*/	'm',		'M',		0,
/* 0x33 - ','		*/	',',		'<',		0,
/* 0x34 - '.'		*/	'.',		'>',		0,
/* 0x35 - '/'		*/	'/',		'?',		KEY_PAD_SLASH,
/* 0x36 - r. SHIFT	*/	KEY_SHIFT_R,	KEY_SHIFT_R,	0,
/* 0x37 - '*'		*/	'*',		'*',    	0,
/* 0x38 - ALT		*/	KEY_ALT_L,	KEY_ALT_L,  	KEY_ALT_R,
/* 0x39 - ' '		*/	' ',		' ',		0,
/* 0x3A - CapsLock	*/	KEY_CAPS_LOCK,	KEY_CAPS_LOCK,	0,
/* 0x3B - F1		*/	KEY_F1,		KEY_F1,		0,
/* 0x3C - F2		*/	KEY_F2,		KEY_F2,		0,
/* 0x3D - F3		*/	KEY_F3,		KEY_F3,		0,
/* 0x3E - F4		*/	KEY_F4,		KEY_F4,		0,
/* 0x3F - F5		*/	KEY_F5,		KEY_F5,		0,
/* 0x40 - F6		*/	KEY_F6,		KEY_F6,		0,
/* 0x41 - F7		*/	KEY_F7,		KEY_F7,		0,
/* 0x42 - F8		*/	KEY_F8,		KEY_F8,		0,
/* 0x43 - F9		*/	KEY_F9,		KEY_F9,		0,
/* 0x44 - F10		*/	KEY_F10,	KEY_F10,	0,
/* 0x45 - NumLock	*/	KEY_NUM_LOCK,	KEY_NUM_LOCK,	0,
/* 0x46 - ScrLock	*/	KEY_SCROLL_LOCK,KEY_SCROLL_LOCK,0,
/* 0x47 - Home		*/	KEY_PAD_HOME,	'7',		KEY_HOME,
/* 0x48 - CurUp		*/	KEY_PAD_UP,	'8',		KEY_UP,
/* 0x49 - PgUp		*/	KEY_PAD_PAGEUP,	'9',		KEY_PAGEUP,
/* 0x4A - '-'		*/	KEY_PAD_MINUS,	'-',		0,
/* 0x4B - Left		*/	KEY_PAD_LEFT,	'4',		KEY_LEFT,
/* 0x4C - MID		*/	KEY_PAD_MID,	'5',		0,
/* 0x4D - Right		*/	KEY_PAD_RIGHT,	'6',		KEY_RIGHT,
/* 0x4E - '+'		*/	KEY_PAD_PLUS,	'+',		0,
/* 0x4F - End		*/	KEY_PAD_END,	'1',		KEY_END,
/* 0x50 - Down		*/	KEY_PAD_DOWN,	'2',		KEY_DOWN,
/* 0x51 - PgDown	*/	KEY_PAD_PAGEDOWN,'3',		KEY_PAGEDOWN,
/* 0x52 - Insert	*/	KEY_PAD_INS,	'0',		KEY_INSERT,
/* 0x53 - Delete	*/	KEY_PAD_DOT,	'.',		KEY_DELETE,
/* 0x54 - Enter		*/	0,		0,		0,
/* 0x55 - ???		*/	0,		0,		0,
/* 0x56 - ???		*/	0,		0,		0,
/* 0x57 - F11		*/	KEY_F11,	KEY_F11,	0,	
/* 0x58 - F12		*/	KEY_F12,	KEY_F12,	0,	
/* 0x59 - ???		*/	0,		0,		0,	
/* 0x5A - ???		*/	0,		0,		0,	
/* 0x5B - ???		*/	0,		0,		KEY_GUI_L,	
/* 0x5C - ???		*/	0,		0,		KEY_GUI_R,	
/* 0x5D - ???		*/	0,		0,		KEY_APPS,	
/* 0x5E - ???		*/	0,		0,		0,	
/* 0x5F - ???		*/	0,		0,		0,	
/* 0x60 - ???		*/	0,		0,		0,
/* 0x61 - ???		*/	0,		0,		0,	
/* 0x62 - ???		*/	0,		0,		0,	
/* 0x63 - ???		*/	0,		0,		0,	
/* 0x64 - ???		*/	0,		0,		0,	
/* 0x65 - ???		*/	0,		0,		0,	
/* 0x66 - ???		*/	0,		0,		0,	
/* 0x67 - ???		*/	0,		0,		0,	
/* 0x68 - ???		*/	0,		0,		0,	
/* 0x69 - ???		*/	0,		0,		0,	
/* 0x6A - ???		*/	0,		0,		0,	
/* 0x6B - ???		*/	0,		0,		0,	
/* 0x6C - ???		*/	0,		0,		0,	
/* 0x6D - ???		*/	0,		0,		0,	
/* 0x6E - ???		*/	0,		0,		0,	
/* 0x6F - ???		*/	0,		0,		0,	
/* 0x70 - ???		*/	0,		0,		0,	
/* 0x71 - ???		*/	0,		0,		0,	
/* 0x72 - ???		*/	0,		0,		0,	
/* 0x73 - ???		*/	0,		0,		0,	
/* 0x74 - ???		*/	0,		0,		0,	
/* 0x75 - ???		*/	0,		0,		0,	
/* 0x76 - ???		*/	0,		0,		0,	
/* 0x77 - ???		*/	0,		0,		0,	
/* 0x78 - ???		*/	0,		0,		0,	
/* 0x78 - ???		*/	0,		0,		0,	
/* 0x7A - ???		*/	0,		0,		0,	
/* 0x7B - ???		*/	0,		0,		0,	
/* 0x7C - ???		*/	0,		0,		0,	
/* 0x7D - ???		*/	0,		0,		0,	
/* 0x7E - ???		*/	0,		0,		0,	
/* 0x7F - ???		*/	0,		0,		0
};

#define LEN_TTY_BUF	100
#define NUM_tty	4
struct tty {
	u8_t	buf[LEN_TTY_BUF];
	u32_t	cursor;
	int	head;
	int	cooked_f, echo_f;
	int	wait_pid;
};

static struct tty *cur_tty;
static struct tty ttys[NUM_tty];

void init_tty()
{
	int i;
	for(i = 0; i < NUM_tty; i++) {
		ttys[i].cursor = 0;
		ttys[i].head = 0;
		ttys[i].cooked_f = 1;
		ttys[i].echo_f = 1;
		ttys[i].wait_pid = 0;
	}
	cur_tty = &ttys[0];
	ttys[0].cursor = 20 * 80;
}

static void print_ch(char ch)
{
	switch(ch) {
	case '\n':
		cur_tty->cursor = (cur_tty->cursor / 80 + 1) * 80;
		break;
	case '\b':
		if(cur_tty->cursor > 0) {
			cur_tty->cursor--;
			set_char(cur_tty->cursor, ' ');
		}
		break;
	default:
		set_char(cur_tty->cursor, ch);
		cur_tty->cursor++;
	}

	if(cur_tty->cursor >= 80 * 25) {
		roll_back();
		cur_tty->cursor -= 80;
	}
	set_cursor(cur_tty->cursor);
}

void keyboard_int_handle()
{
	u8_t code;
	int jndex;
	char ch;
	static int flag_shift = 0;

	code = in_a(PORT_KB_DATA);
	if(code == 0xE0) {
		code = in_a(PORT_KB_DATA);
		jndex = 2;
	} else {
		jndex = flag_shift ? 1 : 0;
	}

	if(cur_tty->wait_pid == 0)
		return;

	if(cur_tty->cooked_f) {

		switch(code & 0x7F) {
		case KEY_SHIFT_L:
		case KEY_SHIFT_R:
			flag_shift = (code & 0x80) ? 0 : 1;
			break;

		default:
			if(code & 0x80)
				break;
			ch = keymap[code][jndex];

			if(ch == KEY_BACKSPACE) {
				if(cur_tty->head > 0)
					cur_tty->head--;
				else
					return;
			} else if(ch == KEY_ENTER) {
				cur_tty->buf[cur_tty->head] = '\0';
				cur_tty->head = 0;
				wake_up(cur_tty->wait_pid);
				cur_tty->wait_pid = 0;
			} else {
				cur_tty->buf[cur_tty->head++] = ch;
			}

			if(cur_tty->echo_f)
				print_ch(ch);
		}
	}
}

void read_tty(char *buf)
{
	cur_tty->wait_pid = current->pid;
	pause();
	strcpy(buf, cur_tty->buf);
}

void write_tty(const char *buf)
{
	char ch;
	int i = 0;
	while((ch = buf[i++]) != '\0')
		print_ch(ch);
}

void printk(const char *fmt, ...)
{
	char buf[100];
	u32_t *argv = (u32_t *)(&fmt) + 1;
	vsprintf(buf, fmt, argv);
	write_tty(buf);
}
